﻿using System;
using System.Text;

public class ConversionBetweenNumeralSystems
{
    public static void Main()
    {
        int from;
        string number;
        string minus = "";
        int to;
        StringBuilder startingDescription = new StringBuilder("Problem 7: Conversion between Numeral Systems");
        StringBuilder description = new StringBuilder(startingDescription.ToString());

        do
        {
            Console.Clear();
            number = InputNumber(description.ToString(), -1);
            description.Append("\n");
            if (number[0] == '-')
            {
                minus = "-";
                number = number.Remove(0, 1);
            }

            number = RemoveLeadingZeros(number);
            if (number == "0")
                minus = "";

            description.Append(minus + number + "(");

            do
            {
                from = InputNumeralSystem(description.ToString());
            } while (!IsNumber(number, from));

            if (IsNumber(number, from))
            {
                to = InputNumeralSystem(description.Append(from).ToString() + ") convert to (");
                Console.Clear();
                Console.WriteLine(description.ToString() + ") = " + Convert(number, from, to) + "(" + to + ")");
                break;
            }
            else
            {
                description.Clear();
                description.Append(startingDescription.ToString());
            }
        } while (true);
    }

    public static string InputNumber(string description, int from = 36)
    {
        string number;

        do
        {
            Console.Clear();
            Console.Write("{0}\nNumber" + (from != -1 ? "({1}) " : "") + ": ", description, from);
            number = Console.ReadLine();
            if (IsNumber(number, from != -1 ? from : 36))
                return number;
        } while (true);
    }

    private static bool IsNumber(string number, int from = 36)
    {
        int digit;

        if ((number == null) || (number.Length < 1))
            return false;
        else
        {
            for (int i = 0; i < number.Length; i++)
            {
                digit = (int)number[i];

                if ((90 < digit) || ((57 < digit) && (digit < 65))
                        || (digit < 45) || ((45 < digit) && (digit < 48))
                            || ((i != 0) && (digit == 45)))
                    return false;

                if (57 < digit)
                    digit -= 7;

                if (from <= digit - 48)
                    return false;
            }

            return true;
        }
    }

    public static string RemoveLeadingZeros(string number)
    {
        int leadingZeros = 1;

        if (number[0] == '0')
        {
            for (int i = 1; i < number.Length; i++)
            {
                if (number[i] != '0')
                    break;

                leadingZeros++;
            }

            if (leadingZeros < number.Length)
                number = number.Remove(0, leadingZeros);
            else
                number = "0";
        }

        return number;
    }

    public static int InputNumeralSystem(string description, int bottom = 2, int top = 36)
    {
        int system;

        if ((bottom < 2) || (36 < bottom) || (top < 2) || (36 < top))
            throw new ArgumentException("It is IMPOSSIBLE one of the both numeral systems to be out of range [2, 36] of naturals!");

        do
        {
            Console.Clear();
            Console.Write(description);
            if (int.TryParse(Console.ReadLine(), out system) && (bottom <= system) && (system <= top))
                return system;
        } while (true);
    }

    public static string Convert(string number, int from, int to)
    {
        int inDecimal;

        if ((from < 2) || (36 < from) || (to < 2) || (36 < to))
            throw new ArgumentException("It is IMPOSSIBLE one of the both numeral systems to be out of range [2, 36] of naturals!");

        inDecimal = ToDecimal(from, number);

        return to == 10 ? inDecimal.ToString() : FromDecimalToNewSystem(inDecimal, to);
    }

    public static int ToDecimal(int from, string number)
    {
        int inDecimal = 0;
        int digit;

        for (int i = 0; i < number.Length; i++)
        {
            digit = (int)number[i] - 48;

            if ((0 <= digit) && (digit <= 9) && (digit < from))
                inDecimal += digit * (int)Math.Pow(from, number.Length - 1 - i);
            else if ((17 <= digit) && (digit <= 42) && (digit - 7 < from))
                inDecimal += (digit - 7) * (int)Math.Pow(from, number.Length - 1 - i);
            else
                throw new ArgumentException("It is IMPOSSIBLE " + number + "(" + from + ") !");
        }

        return inDecimal;
    }

    public static string FromDecimalToNewSystem(int inDecimal, int to)
    {
        int remainder;
        StringBuilder inNewSystem = new StringBuilder();

        do
        {
            remainder = inDecimal % to;
            if (9 < remainder)
                remainder += 7;

            inNewSystem.Append((char)(48 + remainder));
            inDecimal /= to;
        } while (0 < inDecimal);

        for (int i = inNewSystem.Length - 2; i >= 0; i--)
            inNewSystem.Append(inNewSystem[i]);

        return inNewSystem.Remove(0, (inNewSystem.Length - 1) / 2).ToString();
    }
}